package com.zyx.javademo.nio.buffer;

import org.junit.Test;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author Yaxi.Zhang
 * @since 2021/9/17 16:59
 */
public class BufferOperationTest {

    static private final int START = 0;
    static private final int SIZE = 1024;

    /**
     * 缓存切片
     */
    @Test
    public void testSlice() {

        ByteBuffer buffer = ByteBuffer.allocate(10);

        // 缓冲区中的数据 0-9
        for (int i = 0; i < buffer.capacity(); ++i) {
            buffer.put((byte) i);
        }

        // 创建子缓冲区
        buffer.position(3);
        buffer.limit(7);
        ByteBuffer slice = buffer.slice();

        // 改变子缓冲区的内容
        for (int i = 0; i < slice.capacity(); ++i) {
            byte b = slice.get(i);
            b *= 10;
            slice.put(i, b);
        }

        System.out.println("capacity: " + buffer.capacity());
        System.out.println("position: " + buffer.position());
        System.out.println("limit: " + buffer.limit());
        buffer.position(0);
        buffer.limit(buffer.capacity());

        System.out.println("==========================");

        while (buffer.remaining() > 0) {
            System.out.println(buffer.get());
        }

    }

    /**
     * 只读缓存区
     */
    @Test
    public void testReadOnlyBuffer() {
        ByteBuffer buffer = ByteBuffer.allocate(10);

        // 缓冲区中的数据 0-9
        for (int i = 0; i < buffer.capacity(); ++i) {
            buffer.put((byte) i);
        }

        // 创建只读缓冲区
        ByteBuffer readonly = buffer.asReadOnlyBuffer();

        // 改变原缓冲区的内容
        for (int i = 0; i < buffer.capacity(); ++i) {
            byte b = buffer.get(i);
            b *= 10;
            buffer.put(i, b);
        }

        readonly.position(0);
        readonly.limit(buffer.capacity());

        // 只读缓冲区的内容也随之改变
        while (readonly.hasRemaining()) {
            System.out.println(readonly.get());
        }

        // 尝试修改只读缓冲区的内容, 报错: java.nio.ReadOnlyBufferException
        /*final byte b = readonly.get(3);
        readonly.put(3, b);*/
    }

    /**
     * 直接缓冲区
     */
    @Test
    public void testAllocateDirect() throws Exception {

        String infile = "input/nio/read01.txt";
        FileInputStream fin = new FileInputStream(infile);
        FileChannel fcin = fin.getChannel();

        String outfile = "input/nio/write01.txt";
        FileOutputStream fout = new FileOutputStream(outfile);
        FileChannel fcout = fout.getChannel();

        // 使用allocateDirect, 而不是allocate
        ByteBuffer buffer = ByteBuffer.allocateDirect(4);

        while (true) {
            buffer.clear();
            int r = fcin.read(buffer);

            if (r == -1) {
                break;
            }

            System.out.println("读取的长度为:" + r);

            buffer.flip();
            fcout.write(buffer);
        }

    }

    /**
     * 内存映射
     */
    @Test
    public void testMemoryMap() throws IOException {
        RandomAccessFile raf = new RandomAccessFile("input/nio/read02.txt", "rw");

        FileChannel fc = raf.getChannel();
        MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, START, SIZE);

        mbb.put(0, (byte) 97);
        mbb.put(1023, (byte) 122);

        raf.close();
    }

}